package com.lzy.cloud.base.facade;

import com.lzy.cloud.base.constants.CouponConstants;
import com.lzy.cloud.base.constants.RedisPrefix;
import com.lzy.cloud.base.dto.BaseCouponDto;
import com.lzy.cloud.base.remote.MemberApi;
import com.lzy.cloud.base.remote.SmsApi;
import com.lzy.cloud.base.remote.dtos.MemberCouponDto;
import com.lzy.cloud.base.remote.dtos.MemberUserDto;
import com.lzy.cloud.base.remote.request.TmpSmsSendRequest;
import com.lzy.cloud.base.service.CouponService;
import com.lzy.framework.core.ensure.Ensure;
import com.lzy.framework.core.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.*;

@Component
@Slf4j
public class CouponFacade {

    private static final Logger logger = LoggerFactory.getLogger(CouponFacade.class);

    @Autowired
    private CouponService couponService;

    @Autowired
    private MemberApi memberApi;

    @Autowired
    private SmsApi smsApi;

    public List<Long> insert(BaseCouponDto baseCouponDto) {
        List<Long> couponIdList = new ArrayList<>();
        //验证批次、类型编码是否被占用
        BaseCouponDto dto = new BaseCouponDto();
        dto.setTypeCode(baseCouponDto.getTypeCode());
        dto.setBatch(baseCouponDto.getBatch());
        dto.setType(baseCouponDto.getType());
        dto.setCategory(baseCouponDto.getCategory());
        List<BaseCouponDto> list = couponService.queryList(dto);
        if (list != null && list.size() > 0) {
            Ensure.that(list.size()).isNotGt(0, "00040006");
        }
        //券号组装
        String code = "";
        if (baseCouponDto.getCategory() != null && baseCouponDto.getCategory().equals(3)) {
            code = "MR";
        } else if (baseCouponDto.getCategory() != null && baseCouponDto.getCategory().equals(4)){
            code = "OR";
        } else {
            if (baseCouponDto.getType() == 1) {
                code = "PR";
            }
            if (baseCouponDto.getType() == 2) {
                code = "VR";
            }
        }
        code = code + baseCouponDto.getTypeCode() + baseCouponDto.getBatch();
        int[] numbers = RandomUtils.randomCommon(1, 99999, baseCouponDto.getNumber());
        //激活码
        int[] acCode = RandomUtils.randomCommon(1, 999999, baseCouponDto.getNumber());
        //截止时间
        SimpleDateFormat myFmt = new SimpleDateFormat("yyyy-MM-dd");
        Calendar cl = Calendar.getInstance();
        cl.setTime(new Date());

        Integer validTime = baseCouponDto.getValidTime();
        //按生成时间计时
        if (baseCouponDto.getMode() == null)
            baseCouponDto.setMode(2);
        if (baseCouponDto.getMode() != null && baseCouponDto.getMode().equals(2)) {
            if (validTime >= 1) {
                validTime = baseCouponDto.getValidTime() - 1;
                cl.add(Calendar.DATE, validTime);
                String expiryTime = myFmt.format(cl.getTime()) + " 23:59:59";
                baseCouponDto.setExpiryTime(expiryTime);
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
                baseCouponDto.setStartTime(df.format(new Date()));
            }
        }
        for (int i = 0; i < baseCouponDto.getNumber(); i++) {
            //尾号5位随机数
            String couponCode = code + StringUtil.leftPad(numbers[i], 5, '0');
            baseCouponDto.setCode(couponCode);
            String activationCode = StringUtil.leftPad(acCode[i], 6, '0');
            baseCouponDto.setActivationCode(activationCode);
            Long couponId = couponService.insert(baseCouponDto);
            couponIdList.add(couponId);
        }
        return couponIdList;
    }
    /**
     *卡券（房车券，房车代金券)状态修改为已过期
     */
    public Boolean updateExpiredStatus(){
        // 获取分布式锁,如存在，不执行（说明已由其他线程执行）
        Ensure.that(RedisUtils.exists(RedisPrefix.JOB_COUPON_EXPIRED_SCANNING)).isFalse("00000003");
        //先上锁，然后开始执行任务(自动过期，过期时间建议设置为任务周期的1/5)
        RedisUtils.setExpire(RedisPrefix.JOB_COUPON_EXPIRED_SCANNING, 12);
        String categorys = CouponConstants.Category.CAR_COUPON + "," + CouponConstants.Category.CAR_CASH_COUPON;
        List<BaseCouponDto> couponDtoList = couponService.selectNotExpiredCoupon(categorys);
        if(couponDtoList != null && couponDtoList.size() > 0){
            for (BaseCouponDto couponDto:couponDtoList) {
                if(StringUtil.isNotEmpty(couponDto.getExpiryTime())){
                    Boolean ok = compareTime(couponDto.getExpiryTime());
                    if(ok){
                        //说明卡券已过期，更新卡券状态
                        couponDto.setStatus(CouponConstants.CouponStatus.EXPIRED.getCode());
                        couponService.update(couponDto);
                    }
                }
            }
        }
        return true;
    }

    /**
     * 卡券截止时间与当前时间比较
     * @param time
     * @return true 卡券已过期  false 卡券未过期
     */
    public Boolean compareTime(String time){
        String now = DateUtil.fromDateH();
        Integer i = now.compareTo(time);
        if(i<0){
            return false;
        }
        return true;
    }

    /**
     *  执行券(房车券，房车代金券)状态变更任务（即将过期状态的更新）（提前三个月）
     */
    public Boolean updateExpiringStatusThree(){
        try {
        // 获取分布式锁,如存在，不执行（说明已由其他线程执行）
        Ensure.that(RedisUtils.exists(RedisPrefix.JOB_COUPON_EXPIRING_THREE)).isFalse("00000003");
        //先上锁，然后开始执行任务(自动过期，过期时间建议设置为任务周期的1/5)
        RedisUtils.setExpire(RedisPrefix.JOB_COUPON_EXPIRING_THREE, 12);
        String categorys = CouponConstants.Category.CAR_COUPON + "," + CouponConstants.Category.CAR_CASH_COUPON;
        List<BaseCouponDto> couponDtoList = couponService.selectBindCoupon(categorys);
        if (couponDtoList != null && couponDtoList.size() > 0) {
            List<Long> list = this.checkDate(couponDtoList, 3);
            //TODO:第三方短信接口还没有确定。
//            this.addTemSmsSend(list, RedisPrefix.COUPON_EXPIRE_REMIND_THREE.getVal());
            logger.debug("========= 任务调度器正在执行 [ updateCouponStatus ]，共有 " + list.size() + " 张房车券被成功执行更新为即将过期状态...");
        }
        } catch (Exception e)
        {
            logger.error("job [ updateExpiringStatusThree ] 执行出现异常 : " + e.getMessage());
        }
        return true;
    }

    /**
     *  执行券(房车券，房车代金券)状态变更任务（即将过期状态的更新）（提前两个月）
     */
    public Boolean updateExpiringStatusTwo(){
        try {
            // 获取分布式锁,如存在，不执行（说明已由其他线程执行）
            Ensure.that(RedisUtils.exists(RedisPrefix.JOB_COUPON_EXPIRING_TWO)).isFalse("00000003");
            //先上锁，然后开始执行任务(自动过期，过期时间建议设置为任务周期的1/5)
            RedisUtils.setExpire(RedisPrefix.JOB_COUPON_EXPIRING_TWO, 12);
            String categorys = CouponConstants.Category.CAR_COUPON + "," + CouponConstants.Category.CAR_CASH_COUPON;
            List<BaseCouponDto> couponDtoList = couponService.selectBindCoupon(categorys);
            if (couponDtoList != null && couponDtoList.size() > 0) {
                List<Long> list = this.checkDate(couponDtoList, 2);
                //TODO:第三方短信接口还没有确定。
//            this.addTemSmsSend(list, RedisPrefix.COUPON_EXPIRE_REMIND_THREE.getVal());
                logger.debug("========= 任务调度器正在执行 [ updateCouponStatus ]，共有 " + list.size() + " 张房车券被成功执行更新为即将过期状态...");
            }
        } catch (Exception e)
        {
            logger.error("job [ updateExpiringStatusTwo ] 执行出现异常 : " + e.getMessage());
        }
        return true;
    }

    /**
     *  执行券(房车券，房车代金券)状态变更任务（即将过期状态的更新）（提前一个月）
     */
    public Boolean updateExpiringStatusOne(){
        try {
            // 获取分布式锁,如存在，不执行（说明已由其他线程执行）
            Ensure.that(RedisUtils.exists(RedisPrefix.JOB_COUPON_EXPIRING_ONE)).isFalse("00000003");
            //先上锁，然后开始执行任务(自动过期，过期时间建议设置为任务周期的1/5)
            RedisUtils.setExpire(RedisPrefix.JOB_COUPON_EXPIRING_ONE, 12);
            String categorys = CouponConstants.Category.CAR_COUPON + "," + CouponConstants.Category.CAR_CASH_COUPON;
            List<BaseCouponDto> couponDtoList = couponService.selectBindCoupon(categorys);
            if (couponDtoList != null && couponDtoList.size() > 0) {
                List<Long> list = this.checkDate(couponDtoList, 2);
                //TODO:第三方短信接口还没有确定。
//            this.addTemSmsSend(list, RedisPrefix.COUPON_EXPIRE_REMIND_THREE.getVal());
                logger.debug("========= 任务调度器正在执行 [ updateCouponStatus ]，共有 " + list.size() + " 张房车券被成功执行更新为即将过期状态...");
            }
        } catch (Exception e)
        {
            logger.error("job [ updateExpiringStatusTwo ] 执行出现异常 : " + e.getMessage());
        }
        return true;
    }

    /**
     * 将数据存入tmp_sms_send表中
     *
     * @param list
     * @param type
     * @return
     */
    public Boolean addTemSmsSend(List<Long> list, Integer type) {
        Boolean flag = Boolean.FALSE;
        //将数据存入tmp_sms_send表中
        Map<String, Integer> map = new HashMap<>();
        for (Long memberId : list) {
            MemberUserDto memberUserDto = DozerUtils.map(memberApi.findByMemberId(memberId).getResult(),MemberUserDto.class);
            Ensure.that(memberUserDto).isNotNull("00000005");
            if (map.containsKey(memberUserDto.getPhone())) {//判断是否已经有该数值，如有，则将次数加1
                map.put(memberUserDto.getPhone(), map.get(memberUserDto.getPhone()).intValue() + 1);
            } else {
                map.put(memberUserDto.getPhone(), 1);
            }
        }
        for (String k : map.keySet()) {
            TmpSmsSendRequest tmpSmsSendRequest = new TmpSmsSendRequest();
            tmpSmsSendRequest.setBusiType(type);
            tmpSmsSendRequest.setNumber(String.valueOf(map.get(k)));
            tmpSmsSendRequest.setPhone(k);
            Boolean ok = DozerUtils.map(smsApi.add(tmpSmsSendRequest).getResult(),Boolean.class);
            Ensure.that(flag).isTrue("00000004");
        }
        return flag;
    }

    /**
     * 根据时间和券列表，返回即将过期的全对应的会员编号列表
     *
     * @param couponList
     * @param num
     * @return
     * @throws Exception
     */
    public List<Long> checkDate(List<BaseCouponDto> couponList, Integer num) throws Exception {
        Date dNow = new Date();   //当前时间
        Calendar calendar = Calendar.getInstance(); //得到日历
        List<Long> list = new ArrayList<>();
        if (couponList != null && couponList.size() > 0) {
            for (int i = 0; i < couponList.size(); i++) {
                //取得第i+1个数据得到截止时间并转化格式
                String date = couponList.get(i).getExpiryTime();
                if (date != null) {
                    if (date.endsWith(".0")) {
                        date = date.substring(0, date.lastIndexOf("."));
                    }
                    Date end = DateUtil.formatStrToDateTime(date);
                    Ensure.that(end).isNotNull("16010003");
                    calendar.setTime(end);//把截止时间赋给日历
                    int month = calendar.get(Calendar.MONTH);
                    //当月份小于3时，年份减一，月份加9
                    if (month <= num) {
                        calendar.add(calendar.YEAR, -1);
                        calendar.add(calendar.MONTH,  12-num);
                    } else {
                        calendar.add(calendar.MONTH, -1 * num);  //设置为前num个月
                    }
                    Date dBefore = calendar.getTime();   //得到前3月的时间
                    Date defaultStartDate = DateUtil.formatStrToDateTime(DateUtil.formatDateTimeToStr(dBefore));    //格式化前3月的时间
                    Date now = DateUtil.formatStrToDateTime(DateUtil.formatDateTimeToStr(dNow));     //格式化当前时间

                    //将距离到期时间与当前时间比较，如果早于当前时间，则数据更新状态（更新为即将到期状态）
                    if (-90000000 < (defaultStartDate.getTime() - now.getTime()) && (defaultStartDate.getTime() - now.getTime()) <= 0) {
                        BaseCouponDto couponDto = new BaseCouponDto();
                        couponDto.setId(couponList.get(i).getId());
                        couponDto.setStatus(CouponConstants.CouponStatus.EXPIRING.getCode());
                        Boolean flag = couponService.update(couponDto);
                        if (flag) {
                            //根据couponId获取会员ID
                            MemberCouponDto memberCouponDto = DozerUtils.map(memberApi.findByCouponId(couponDto.getId()).getResult(),MemberCouponDto.class);
                            if(memberCouponDto != null && memberCouponDto.getMemberId() != null) {
                                list.add(memberCouponDto.getMemberId());
                            }
                        }
                    }
                }
            }
        }
        return list;
    }
}
